pub fn step(x: f64, _params: &Option<Vec<f64>>) -> f64 {
    let lt1 = -5.0f64;
    let gte1 = 5.0f64;
    match x < 1.0f64 {
        true => lt1,
        false => gte1,
    }
}

pub fn disco_line(x: f64, _params: &Option<Vec<f64>>) -> f64 {
    let slope = 1.0f64;
    let intercept = 1.0f64;
    let disco_pt = 1.0f64;
    let abs_difference = (x - disco_pt).abs();
    let tol: f64 = 1.0e-15;
    match abs_difference < tol {
        true => -10.0f64,
        false => slope * x + intercept,
    }
}

pub fn line(x: f64, params: &Option<Vec<f64>>) -> f64 {
    let mut slope = 1.0f64;
    let mut intercept = 0.0f64;
    match params {
        Some(x) => match x.len() {
            1 => {
                intercept = x[0];
            }
            2 => {
                intercept = x[0];
                slope = x[1];
            }
            _ => {}
        },
        None => {}
    };
    slope * x + intercept
}

pub fn log(x: f64, params: &Option<Vec<f64>>) -> f64 {
    let mut base = f64::exp(1.0f64);
    match params {
        Some(x) => match x.len() {
            1 => {
                base = x[0];
            }
            _ => {}
        },
        None => {}
    };
    x.ln() / base.ln()
}

pub fn logpow(x: f64, params: &Option<Vec<f64>>) -> f64 {
    let mut base = f64::exp(1.0f64);
    let mut pow = 1.0f64;
    match params {
        Some(x) => match x.len() {
            1 => {
                base = x[0];
            }
            2 => {
                base = x[0];
                pow = x[1];
            }
            _ => {}
        },
        None => {}
    };
    (x.ln() / base.ln()).powf(pow)
}

pub fn rational_poly(x: f64, _params: &Option<Vec<f64>>) -> f64 {
    (x.powi(2) + 1.0f64) / (x - 1.0f64)
}

pub fn poly(x: f64, params: &Option<Vec<f64>>) -> f64 {
    match params {
        Some(p) => p
            .iter()
            .enumerate()
            .map(|(ix, &a)| a * x.powi(ix.try_into().unwrap()))
            .sum(),
        None => x,
    }
}
